package cz.cvut.kadledav.paa.weight3sat.util;

import cz.cvut.kadledav.paa.weight3sat.SimulatedAnnealing;
import cz.cvut.kadledav.paa.weight3sat.bo.ComputedInstanceSolution;
import cz.cvut.kadledav.paa.weight3sat.bo.Instance;
import cz.cvut.kadledav.paa.weight3sat.bo.SolutionState;

import java.util.*;

/**
 * User: David Kadlecek
 * Date: 7.10.13
 */
public class TaskUtil {

    public static String SPECIAL_INSTANCE = "instance";

    public static ComputedInstanceSolution measureTask(Instance instance,Map<String,Object> params) {

        SimulatedAnnealing simulatedAnnealing = new SimulatedAnnealing(instance,params);

        ComputedInstanceSolution solution = new ComputedInstanceSolution(instance);
        long startTime = System.currentTimeMillis();
        simulatedAnnealing.compute();
        solution.setTime((int) (System.currentTimeMillis() - startTime));
        solution.setSolution(simulatedAnnealing.getResult());
        return solution;
    }

    public static void run(int times, int clauseSize, int variables, Map<String, Object> params) {
        List<Instance> instances = InstanceLoader.loadInstancesOwn(clauseSize,variables);
        Map<Instance, SolutionState> bestSolutions = new HashMap<>(instances.size());
        Map<Instance, SolutionState> worstSolutions = new HashMap<>(instances.size());
        int time = 0;
        boolean computeT0 = !params.containsKey(SimulatedAnnealing.START_TEMPERATURE);
        int biggestDiff = -1;
        SolutionState biggestDiffWorst = null;
        SolutionState biggestDiffBest = null;

        int special = -1;
        if(params.containsKey(SPECIAL_INSTANCE)){
            special = Integer.valueOf(params.get(SPECIAL_INSTANCE).toString());
        }

        TreeSet<Instance> allInstances = new TreeSet<>();
        List<SolutionState> badStates = new ArrayList<>();
        for (int i = 0; i < times; i++) {
            for (int j = 0; j < instances.size(); j++) {
                if(special>=0 && j!= special){
                    continue;
                }
                Instance instance = instances.get(j);
                allInstances.add(instance);
                if(computeT0){
                    params.put(SimulatedAnnealing.START_TEMPERATURE,instance.getVariableWeightSum()*(instance.getClauses().size()+1));
                }
                ComputedInstanceSolution computedInstanceSolution = measureTask(instance,params);
                time += computedInstanceSolution.getTime();
                SolutionState resultState = computedInstanceSolution.getSolution();
                if(resultState.getNumberOfUnsatisfiableClauses()>0){
                    badStates.add(resultState);
                }
                if (!bestSolutions.containsKey(instance)) {
                    bestSolutions.put(instance, resultState);
                    worstSolutions.put(instance, resultState);
                } else {
                    if (resultState.isBetterThan(bestSolutions.get(instance))) {
                        bestSolutions.put(instance, resultState);
                    }
                    if (worstSolutions.get(instance).isBetterThan(resultState)) {
                        worstSolutions.put(instance, resultState);
                    }
                }
                int newDiff = bestSolutions.get(instance).getOptCriteria() - worstSolutions.get(instance).getOptCriteria();
                if (newDiff > biggestDiff) {
                    biggestDiff = newDiff;
                    biggestDiffBest = bestSolutions.get(instance);
                    biggestDiffWorst = worstSolutions.get(instance);
                }
            }
        }
        time = time / (times * instances.size());
        System.out.println("avg time [ms]: "+time);
        System.out.println("max diff:"+biggestDiff);
        System.out.println("worst:"+biggestDiffWorst.getNumberOfUnsatisfiableClauses() + ","+biggestDiffWorst.getWeight()+" , "+biggestDiffWorst.getOptCriteria()+ " id:"+biggestDiffWorst.getInstance().getId());
        System.out.println("best:"+biggestDiffBest.getNumberOfUnsatisfiableClauses() + ","+biggestDiffBest.getWeight()+" , "+biggestDiffBest.getOptCriteria() + " id:"+biggestDiffBest.getInstance().getId());
        System.out.println("----------------------------");
        Collections.sort(badStates,new Comparator<SolutionState>() {
            @Override
            public int compare(SolutionState o1, SolutionState o2) {
                return o1.getInstance().getId() - o2.getInstance().getId();
            }
        });
        final TreeSet<Instance> badInst = new TreeSet<>();
        final HashMap<Instance, Integer> instanceIntegerHashMap = new HashMap<>();
         for (SolutionState badState : badStates) {
             final Instance instance = badState.getInstance();
             System.out.println("bad: " + badState.getNumberOfUnsatisfiableClauses() + " , " + instance.getId());
            badInst.add(instance);
             int count = 0;
             if(instanceIntegerHashMap.containsKey(instance)){
                 count = instanceIntegerHashMap.get(instance);
            }
            instanceIntegerHashMap.put(instance,count+1);


        }
        System.out.println("failedInst:"+badInst.size());
        System.out.println("failed:"+badStates.size());
        for (Instance instance : badInst) {
            System.out.println("instance id:"+instance.getId()+":"+instanceIntegerHashMap.get(instance));
        }

        System.out.println("--------------------- start solutions -------------------");
        for (Instance instance : allInstances) {
            final SolutionState solutionState = bestSolutions.get(instance);
            System.out.println(instance.getId()+","+instance.getKnowSolution()+","+solutionState.getOptCriteria());
        }
        System.out.println("--------------------- end solutions -------------------");
    }

}
